<?php
/*
*
* BEGIN htmlcodemaker.php
*
*
* Silent Bob Custom Extension - Allows Users to create any type of html content
* @Description: Creates any type of html such as dropdowns, radio buttons, html tables,
 * headings, paragraphs, anchors, images etc and provides the user with properly
 * formatted xhtml string.
 * @Authors: Salman Noor, Wits University
* @Copyright: © Wits University 2011 - All Rights Reserved
* @License: BSD License (http://www.linfo.org/bsdlicense.html)
*
*
* BEGIN CHANGELOG
* Developers working on thee files are REQUIRED to maintain this CHANGELOG.
* Please ensure you follow the Changelog Guidelines: http://gforge.wits.ac.za/gf/project/silentbob/wiki/?&pageid=247
* !==================================================================================================================================================================
*
* VERSION 1.0.0
*	+ Created, Monty, 25 July 2011
*	+ Added functionality to insert html tag attribiutes, Salman, 26 July 2011
*	+ Added functionality to create html element with options such as radio, Salman, 26 July 2011
*	+ Added functionality to create html element with select options such as drop down, Salman, 26 July 2011
*	+ Added functionality to inject one html element into another, Salman, 28 July 2011
*	! Modified html string injection to allow multiple html elements to be injected and not just one (Limitation Dectected in unit testing; see unit test for this file), Salman, 30 June 2011
*       ! Bug Fix as detected from Unit Tests. Fixed logic that handles an exception if text does not exist inside a self closing HTML tag, Salman, 1 August 2011
*       + Added functionality to set default selected options in an array rather than serially, Salman, 1 August 2011
*       ! Bug fix to check if arrays being inserted as arguments are associative, Salman, 3 August 2011
*       + Added funcitonality to inject object for each individual option of checkboxes and radios, Salman, 3 August 2011
*       ! Bug fix in creating drop downs. Thato, 4 August 2011
*       ! Bug fix to inject text inputs other html elements that have special instatiation arguments, Salman, 4 August 2011
*	! Fix Spelling error, Salman Noor, 5 August 2011
*
* ==================================================================================================================================================================!
* END CHANGELOG
*/


/*******************************************************************************************************************************************************************
*
* BEGIN Direct Call Check
*
/******************************************************************************************************************************************************************/
global $doNotCallThisScriptDirectly;
if ($doNotCallThisScriptDirectly != 1)
{
	/* Read the ini language file */
	$ini_lang_array = array();
	$clientlang = explode(",", strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']));
	$lang_ini_array = (file_exists("lang/" . trim($clientlang[0]) . ".ini")) ? parse_ini_file("lang/" . trim($clientlang[0]) . ".ini", true) : parse_ini_file("lang/en.ini", true);
	die ($lang_ini_array['ERRORS']['doNotCallThisScriptDirectly']);
}
/*******************************************************************************************************************************************************************
*
* END Direct Call Check
*
/******************************************************************************************************************************************************************/

/*******************************************************************************************************************************************************************
* BEGIN htmlcodemaker class
/******************************************************************************************************************************************************************/
class htmlcodemaker
{

    /* data members for this class */
    var $type;
    var $attributes;
    var $self_closers;
    var $options;
    var $brk_space_type;
    var $default_selected_options;
    var $option_values;
    var $option_child_objects;

    /* constructor
     * The 'type' argument is mandatory and should be inserted without the
     * angle brackets such as 'img' and not '<img>'
     */
    function htmlcodemaker($type, $self_closers = array('input', 'img', 'hr', 'br', 'meta', 'link','frame'))
    {
        if (isset($type))
        {
            $this->type = strtolower($type);
            $this->self_closers = $self_closers;
        }
        else
        {
            return "Constructor parameters are not initialized properly.";
        }
        $this->default_selected_options = array();
        $this->attributes = array();
        $this->options = array();
        $this->option_values = array();
        $this->option_child_objects = array();
    }

     /*
     * This function can be used to set the break space 
     * between options for radio buttons, checkboxes etc.
     * Make sure that a proper breakspace such as
     * <br> or <hr> or &npsb; is set. Otherwise, it
     * will spit out anything you set it to.
     */
    function setBreakSpaceType($brkSpaceType)
    {
        $this->brk_space_type = $brkSpaceType;
    }

    /*
     * This function is only used once the setOption method has been
     * used and options has been set.
     * This function will set an option to default selected if it
     * exists. More than one option can be set as default.
     */
    function setDefaultOptionWithValue($value)
    {
         if (is_array($value))
        {

             foreach ($value as $actualValue)
             {
                if (array_key_exists($actualValue, $this->options))
                {
                    if (!in_array($actualValue, $this->default_selected_options))
                    {
                        $this->default_selected_options[] = $actualValue;
                    }
                }
             }

        }
        else
        {
            if (array_key_exists($value, $this->options))
            {
                if (!in_array($value, $this->default_selected_options))
                {
                    $this->default_selected_options[] = $value;
                }
            }
        }

    }

    /*
     * This function is used to inset the options for drop downs,
     * list boxes, radio buttons, checkboxes etc. Insert an option
     * with the value and label for the option and spevify whether
     * it is selected by default
     * \note The last argument is optional while the first two arguments
     * are mandatory to insert.
     */
    function setOption($value, $label='', $defaultSelectOption=false,$optionAttributes='')
    {
        if (!is_array($value))
        {
            $this->options[$value] = $label;
            if ($defaultSelectOption)
            {
                if (!in_array($value, $this->default_selected_options))
                {
                    $this->default_selected_options[] = $value;
                }
            }
        } 
        else
        {
            $this->options = array_merge($this->options, $value);
            if ($defaultSelectOption)
            {
                if (!in_array($value, $this->default_selected_options))
                {
                    $this->default_selected_options[] = $value;
                }
            }
        }
        
        if (is_array($optionAttributes))
        {
            if ($this->isAssoc($optionAttributes))
            {
                     $optionValueArray = array();
                foreach ($optionAttributes as $optionLabel => $OptionValue)
                {
                    $optionValueArray[$optionLabel] = $OptionValue;
                }
                $this->option_values[$value] = $optionValueArray;
            }

        }
    }

    /*
     * Check if array is associative
     *
     */
    function isAssoc($arr)
    {
        return array_keys($arr) !== range(0, count($arr) - 1);
    }


    /* get any existing attribiute if it exists in the attribiute array*/
    function get($attribute)
    {
        return $this->attributes[$attribute];
    }

    /*
     * set attribiute in array
     * Can use an associative array with key as the attribiute value as the value of the value of the attribiute
     * Insert this associative array inside the attribiute argument and leave the value arguement blank
     * Can use the arguements given
     */
    function set($attribute, $value = '')
    {
        if (isset($attribute))
        {
            if (!is_array($attribute))
            {
                $this->attributes[$attribute] = $value;
            } 
            else
            {
                if ($this->isAssoc($attribute))
                {
                    $this->attributes = array_merge($this->attributes, $attribute);
                }
            }  
        }

    }

    /* remove an existing attribiute in the attribute array*/
    function remove($att)
    {
        if (isset($this->attributes[$att]))
        {
            unset($this->attributes[$att]);
        }
    }

    /* clear all attribiutes in array*/
    function clear()
    {
        $this->attributes = array();
    }

    /* inject another html element as a text string within an html tag
     * \note Only an object of htmlcodemaker can be inject and needs to
     * either one object or an array of objects
     * \note if multiple options are inserted then the second argument is useful
     * Just insert the value of the option and this will allow you to insert another
     * object within a radio, checkbox, dropdown etc option.
     */
    function inject($object,$parentObject=NULL)
    {

        //Inject into to attribute array inside the text key or option_child_objects
        //array if the parent object is set
        if (!is_array($object))
        {
            if (@get_class($object) == __class__)
            {
                if (isset($parentObject))
                {
                   if (array_key_exists($parentObject, $this->option_child_objects))
                   {
                       $this->option_child_objects[$parentObject] .= $object->output();
                   }
                   else
                   {
                        $this->option_child_objects[$parentObject] = $object->output();
                   }
                           
                }
                else
                {
                    if (array_key_exists('text', $this->attributes))
                    {
                        $this->attributes['text'].= $object->output();
                    }
                    else
                    {
                        $this->attributes['text'] = $object->output();
                    }
                }

            }
        } 
        else
        {
            //If an array of objects are is given as an argument then
            //loop through the array and concatentate these objects into 
            //the text key of the attribiute array
            foreach ($object as $objectToConstruct)
            {

                if (@get_class($objectToConstruct) == __class__)
                {
                    if (isset($parentObject))
                    {
                       if (array_key_exists($parentObject, $this->option_child_objects))
                       {
                           $this->option_child_objects[$parentObject] .= $objectToConstruct->output();
                       }
                       else
                       {
                            $this->option_child_objects[$parentObject] = $objectToConstruct->output();
                       }
                    }
                    else
                    {
                        if (array_key_exists('text', $this->attributes))
                        {
                            $this->attributes['text'].= $objectToConstruct->output();
                        }
                        else
                        {
                            $this->attributes['text'] = $objectToConstruct->output();
                        }
                    }

                }
            }
        }
    }

    /*
     * This function is used to build dropdowns and listboxes.
     * It is called by the output member function of this class.
     */
    function buildElementWithSelectOptions()
    {
        $build = NULL;
        $build .= "<select";
        if (count($this->attributes))
        {
            foreach ($this->attributes as $key => $value)
            {
                if ($key != 'text')
                {
                    $build.= ' ' . $key . '="' . $value . '"';
                }
            }
            $build .= '>';
        }
        foreach ($this->options as $option_value => $option_label)
        {
            $build .= '<option value="' . $option_value . '"';

            if (in_array($option_value, $this->default_selected_options))
            {
                $build .= ' selected="selected"';
            }

             if (array_key_exists($option_value, $this->option_values))
            {
                 $optionValueArray = $this->option_values[$option_value];
                     foreach ($optionValueArray as $distinct_option_value => $distinct_option_label)
                     {
                         $build .= "$distinct_option_value".' ="' . $distinct_option_label . '" ';
                     }
            }

            $build .='>' . $option_label . '</option>';
        }
        $build .= "</select>";
        return $build;
    }

     /*
     * This function is used to build html form elements with options such as
     * radio buttons and checkboxes.
     * 
     * It is called by the output member function of this class.
     */
    function buildElementWithListOfOptions()
    {
        $build = NULL;

        foreach ($this->options as $option_value => $option_label)
        {

            $build .= "<input";

            if (count($this->attributes))
            {
                foreach ($this->attributes as $key => $value)
                {
                    if ($key != 'text')
                    {
                        $build.= ' ' . $key . '="' . $value . '"';
                    }
                }

            }

            if (!array_key_exists('type', $this->attributes))
            {
                $build .= " type =\"" . $this->type . "\" ";
            }
            $build .= ' value ="' . $option_label . '" ';
            if (in_array($option_value, $this->default_selected_options))
            {

                $build .= ' checked="checked"';
            }

            if (array_key_exists($option_value, $this->option_values))
            {
                 $optionValueArray = $this->option_values[$option_value];
                     foreach ($optionValueArray as $distinct_option_value => $distinct_option_label)
                     {
                         $build .= "$distinct_option_value".' ="' . $distinct_option_label . '" ';
                     }
            }
        //    $this->option_values[$value]
                $build .= ">";
            //}
            
             if (array_key_exists($option_value, $this->option_child_objects))
             {
                  $build.= $this->option_child_objects[$option_value];
             }
             else
             {
                if (array_key_exists('text', $this->attributes))
                {
                    $build.= $this->attributes['text'];
                }
                else
                {
                    $build .= $option_label;
                }
             }


            if (isset($this->brk_space_type))
            {
                $build .= $this->brk_space_type;
            }
        }

        return $build;
    }

     /*
     * This function is used to build any html element with a self closing tag
     * such as <button></button>
     * If the element you want to build is inside the 'self_closers' array then
     * the self closing tag will be removed as replaced by '/>' at the end of the
      * html tag.
      * Be aware of the self_closers array and the role it plays.
     */
    function buildElementWithSelfCloser()
    {
        $build = '<' . $this->type;

        //add attributes
        if (count($this->attributes))
        {
            foreach ($this->attributes as $key => $value)
            {
                if ($key != 'text')
                {
                    $build.= ' ' . $key . '="' . $value . '"';
                }
            }
        }

        //closing
        if (!in_array($this->type, $this->self_closers))
        {
            if (array_key_exists('text', $this->attributes))
            {
                $build .= '>' . $this->attributes['text'] . '</' . $this->type . '>';
            }
            else
            {
                $build .= '>' . '</' . $this->type . '>';
            }
        } 
        else
        {
            $build.= ' />';
        }

        //return it
        return $build;
    }

    /*
     * This function is used to spit out simple text strings. It is ussually used
     * it you want to inject a text string into another html element.
     */
    function buildSimpleTextElement()
    {
        //If a text string exists, then retrun it as a string
        if (array_key_exists('text', $this->attributes))
        {
            return $this->attributes['text'];
        }
    }

    /* build depending the the 'type' set*/
    function build()
    {
        switch ($this->type)
        {
            case 'text':
                return $this->buildSimpleTextElement();
                break;
            case 'radio':
            case 'checkbox':
                return $this->buildElementWithListOfOptions();
                break;
            case 'dropdown':
                return $this->buildElementWithSelectOptions();
                break;
            default:
                return $this->buildElementWithSelfCloser();
                break;
        }
    }

    /* spit it out */
    public function output()
    {
        if (array_key_exists('type', $this->attributes))
        {
            if ($this->attributes['type']== 'radio' || $this->attributes['type']=='checkbox' || $this->attributes['type']=='dropdown')
            {
                $this->type = $this->attributes['type'];
            }
        }

        if ($this->type == 'textinput')
        {
            $this->type = 'input';
            $this->attributes['type'] = 'text';
        }

        if ($this->type == 'password')
        {
            $this->type = 'input';
            $this->attributes['type'] = 'password';
        }
        if ($this->type == 'hidden')
        {
            $this->type = 'input';
            $this->attributes['type'] = 'hidden';
        }
        
        return $this->build();
    }

}
/*
 * END htmlcodemaker class
 */

/*
 * END htmlcodemaker.php
 */
?>

